home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xarchie-2.0.9 / FWF / FileChooser / FChooser.c next >
C/C++ Source or Header  |  1995-06-18  |  28KB  |  894 lines

  1. /*
  2.  * FChooser.c : A widget for choosing a file
  3.  *
  4.  * George Ferguson, ferguson@cs.rochester.edu, 21 Jan 1993.
  5.  * Last update: 12 May 1993.
  6.  *
  7.  * This code is derived from the FileSelector widget by Brian Totty,
  8.  * hence the following copyright applies:
  9.  *
  10.  * Copyright 1990,1991,1992 Brian Totty
  11.  * 
  12.  * Permission to use, copy, modify, distribute, and sell this software
  13.  * and its documentation for any purpose is hereby granted without fee,
  14.  * provided that the above copyright notice appears in all copies and that
  15.  * both that copyright notice and this permission notice appear in
  16.  * supporting documentation, and that the name of Brian Totty or
  17.  * University of Illinois not be used in advertising or publicity
  18.  * pertaining to distribution of the software without specific, written
  19.  * prior permission.  Brian Totty and University of Illinois make no
  20.  * representations about the suitability of this software for any
  21.  * purpose.  It is provided "as is" without express or implied warranty.
  22.  *
  23.  * Brian Totty and University of Illinois disclaim all warranties with
  24.  * regard to this software, including all implied warranties of
  25.  * merchantability and fitness, in no event shall Brian Totty or
  26.  * University of Illinois be liable for any special, indirect or
  27.  * consequential damages or any damages whatsoever resulting from loss of
  28.  * use, data or profits, whether in an action of contract, negligence or
  29.  * other tortious action, arising out of or in connection with the use or
  30.  * performance of this software.
  31.  *
  32.  * Author:
  33.  *     Brian Totty
  34.  *     Department of Computer Science
  35.  *     University Of Illinois at Urbana-Champaign
  36.  *    1304 West Springfield Avenue
  37.  *     Urbana, IL 61801
  38.  * 
  39.  *     totty@cs.uiuc.edu
  40.  *     
  41.  */ 
  42.  
  43. #include <X11/Xlib.h>
  44. #include <X11/Xos.h>
  45. #include <X11/IntrinsicP.h>
  46. #include <X11/Intrinsic.h>
  47. #include <X11/StringDefs.h>
  48. #include <X11/cursorfont.h>
  49. #include <X11/CompositeP.h>
  50. #include <X11/Composite.h>
  51. #include <X11/Xaw/MenuButton.h>
  52. #include <X11/Xaw/SimpleMenu.h>
  53. #include <X11/Xaw/SmeBSB.h>
  54. #include <X11/Xaw/Viewport.h>
  55. #include <X11/Xaw/List.h>
  56.  
  57. #include <DirMgr.h>
  58. #include <FChooserP.h>
  59. #include <FChooser.h>
  60.  
  61. #if defined(SYSV) || defined(SVR4)
  62. # ifndef __sgi
  63. #  ifndef getwd
  64. #   define getwd(path) getcwd(path, MAXPATHLEN)
  65. #  endif
  66. # endif
  67. #endif
  68.  
  69. /*---------------------------------------------------------------------------*
  70.  
  71.                    I N T E R N A L    R O U T I N E S
  72.  
  73.  *---------------------------------------------------------------------------*/
  74.  
  75. #if (!NeedFunctionPrototypes)
  76.  
  77. static void        Initialize();
  78. static void        Realize();
  79. static void        Destroy();
  80. static void        Resize();
  81. static Boolean        SetValues();
  82. static XtGeometryResult    GeometryManager();
  83. static void        ChildrenCreate();
  84. static void        ChildrenRealize();
  85. static void        ChildrenUpdate();
  86. static void        DirectoryCallback();
  87. static void        FileCallback();
  88. static void        SelectFileByIndex();
  89. static Boolean        SelectFileByName();
  90. static void        UnselectAll();
  91. static void        Notify();
  92. static void        GotoDeepestLegalDirectory();
  93. static void        UpdateLists();
  94. static void        Chdir();
  95.  
  96. #else
  97.  
  98. static void        Initialize(Widget request, Widget new);
  99. static void        Realize(Widget w, XtValueMask *valueMask,
  100.                 XSetWindowAttributes *attrs);
  101. static void        Destroy(XfwfFileChooserWidget fcw);
  102. static void        Resize(Widget w);
  103. static Boolean        SetValues(Widget current, Widget request, Widget new);
  104. static XtGeometryResult    GeometryManager(Widget w,
  105.                 XtWidgetGeometry *request,
  106.                 XtWidgetGeometry *reply);
  107. static void        ChildrenCreate(XfwfFileChooserWidget fcw);
  108. static void        ChildrenRealize(XfwfFileChooserWidget fcw);
  109. static void        ChildrenUpdate(XfwfFileChooserWidget fcw);
  110. static void        DirectoryCallback(Widget w, XtPointer client_data,
  111.                 XtPointer call_data);
  112. static void        FileCallback(Widget w, XtPointer client_data,
  113.                 XtPointer call_data);
  114. static void        SelectFileByIndex(XfwfFileChooserWidget fcw, int index);
  115. static Boolean        SelectFileByName(XfwfFileChooserWidget fcw, char *name);
  116. static void        UnselectAll(XfwfFileChooserWidget fcw);
  117. static void        Notify(XfwfFileChooserWidget fcw);
  118. static void        GotoDeepestLegalDirectory(XfwfFileChooserWidget fcw);
  119. static void        UpdateLists(XfwfFileChooserWidget fcw);
  120. static void        Chdir(XfwfFileChooserWidget fcw);
  121.  
  122. #endif
  123.  
  124. /*---------------------------------------------------------------------------*
  125.  
  126.               R E S O U R C E    I N I T I A L I Z A T I O N
  127.  
  128.  *---------------------------------------------------------------------------*/
  129.  
  130. #define FCFieldOffset(FIELD)    XtOffset(XfwfFileChooserWidget,fileChooser.FIELD)
  131. #define CoreFieldOffset(FIELD)    XtOffset(Widget,core.FIELD)
  132.  
  133. static XtResource resources[] = {
  134.     { XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
  135.      CoreFieldOffset(width), XtRString, "500" },
  136.     { XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
  137.      CoreFieldOffset(height), XtRString, "250" },
  138.     { XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel),
  139.      CoreFieldOffset(background_pixel), XtRString, "white" },
  140.     { XtNcurrentDirectory, XtCPathname, XtRString, sizeof(String),
  141.      FCFieldOffset(current_dir), XtRString, NULL },
  142.     { XtNcurrentFile, XtCFilename, XtRString, sizeof(String),
  143.      FCFieldOffset(current_file), XtRString, NULL },
  144.     { XtNcallback, XtCCallback, XtRCallback,
  145.      sizeof(XtCallbackList), FCFieldOffset(callbacks), XtRCallback, NULL},
  146.     {XtNsortMode, XtCValue, XtRInt, sizeof(int),
  147.      FCFieldOffset(sort_mode), XtRString, "2"},
  148.     {XtNpattern, XtCFile, XtRString, sizeof(String),
  149.      FCFieldOffset(pattern), XtRString, NULL},
  150. };
  151.  
  152. #undef FCFieldOffset
  153. #undef CoreFieldOffset
  154.  
  155. /*---------------------------------------------------------------------------*
  156.  
  157.                     C L A S S    A L L O C A T I O N
  158.  
  159.  *---------------------------------------------------------------------------*/
  160.  
  161. XfwfFileChooserClassRec xfwfFileChooserClassRec = {
  162.     {
  163.     /* superclass        */    (WidgetClass)&compositeClassRec,
  164.     /* class_name        */    "XfwfFileChooser",
  165.     /* widget_size        */    sizeof(XfwfFileChooserRec),
  166.     /* class_initialize    */    NULL,
  167.     /* class_part_initialize*/    NULL,
  168.     /* class_inited        */    FALSE,
  169.     /* initialize        */    (XtInitProc)Initialize,
  170.     /* initialize_hook    */    NULL,
  171.     /* realize        */    (XtRealizeProc)Realize,
  172.     /* actions        */    NULL,
  173.     /* num_actions        */    0,
  174.     /* resources        */    resources,
  175.     /* resource_count    */    XtNumber(resources),
  176.     /* xrm_class        */    NULLQUARK,
  177.     /* compress_motion    */    TRUE,
  178.     /* compress_exposure    */    TRUE,
  179.     /* compress_enterleave    */    TRUE,
  180.     /* visible_interest    */    FALSE,
  181.     /* destroy        */    (XtWidgetProc)Destroy,
  182.     /* resize        */    (XtWidgetProc)Resize,
  183.     /* expose        */    XtInheritExpose,
  184.     /* set_values        */    (XtSetValuesFunc)SetValues,
  185.     /* set_values_hook    */    NULL,
  186.     /* set_values_almost    */    XtInheritSetValuesAlmost,
  187.     /* get_values_hook    */    NULL,
  188.     /* accept_focus        */    NULL,
  189.     /* version        */    XtVersion,
  190.     /* callback_private    */    NULL,
  191.     /* tm_table        */    NULL,
  192.     /* query_geometry       */    XtInheritQueryGeometry,
  193.     /* display_accelerator  */    XtInheritDisplayAccelerator,
  194.     /* extension            */    NULL
  195.     }, /* Core Part */
  196.     {
  197.     /* geometry_manager     */    GeometryManager,
  198.     /* change_managed       */    XtInheritChangeManaged,
  199.     /* insert_child         */    XtInheritInsertChild,
  200.     /* delete_child         */    XtInheritDeleteChild,
  201.     /* extension            */    NULL
  202.     }, /* Composite Part */        
  203.     {
  204.     /* no extra class data  */    0
  205.     }  /* FileSelector Part */
  206. };
  207.  
  208. WidgetClass xfwfFileChooserWidgetClass =
  209.     (WidgetClass)&xfwfFileChooserClassRec;
  210.  
  211. /*---------------------------------------------------------------------------*
  212.  
  213.                     E X P O R T E D    M E T H O D S
  214.  
  215.  *---------------------------------------------------------------------------*/
  216.  
  217.  
  218. /*---------------------------------------------------------------------------*
  219.  
  220.     Initialize()
  221.  
  222.     This procedure is called by the X toolkit to initialize
  223.     the FileChooser widget instance.  The hook to this routine is in the
  224.     initialize part of the core part of the class.
  225.  
  226.  *---------------------------------------------------------------------------*/
  227.  
  228. /* ARGSUSED */
  229. static void
  230. Initialize(request,new)
  231. Widget request,new;
  232. {
  233.     XfwfFileChooserWidget fcw = (XfwfFileChooserWidget)new;
  234.     char *str,*initial_file,path[MAXPATHLEN + 2];
  235.     static char *star = "*";
  236.  
  237.     FCBusyCursor(fcw) = XCreateFontCursor(XtDisplay(fcw),XC_watch);
  238.     FCDirMenu(fcw) = NULL;
  239.     FCDirMenuButton(fcw) = NULL;
  240.     FCFileList(fcw) = NULL;
  241.     FCDirMgr(fcw) = NULL;
  242.     FCFileNames(fcw) = NULL;
  243.     FCNumFileNames(fcw) = 0;
  244.     FCDirNames(fcw) = NULL;
  245.     FCNumDirNames(fcw) = 0;
  246.  
  247.     str = (char *)XtCalloc((MAXPATHLEN + 2),sizeof(char));
  248.     if (FCCurrentDirectory(fcw) != NULL) {    /* User Specified Path */
  249.     strcpy(str,FCCurrentDirectory(fcw));
  250.     } else {
  251.     getwd(path);
  252.     strcpy(str,path);
  253.     }
  254.     FCCurrentDirectory(fcw) = str;
  255.  
  256.     str = (char *)XtCalloc((MAXPATHLEN + 2),sizeof(char));
  257.     initial_file = FCCurrentFile(fcw);
  258.     FCCurrentFile(fcw) = str;
  259.  
  260.     if (FCCorePart(request)->width <= 0)
  261.     FCCorePart(new)->width = 500;
  262.     if (FCCorePart(request)->height <= 0)
  263.     FCCorePart(new)->height = 200;
  264.  
  265.     if (FCPattern(fcw) == NULL)
  266.     FCPattern(fcw) = star;
  267.     FCPattern(fcw) = XtNewString(FCPattern(fcw));
  268.  
  269.     ChildrenCreate(fcw);
  270.     GotoDeepestLegalDirectory(fcw);
  271.     if (initial_file)
  272.     SelectFileByName(fcw,initial_file);
  273. } /* End Initialize */
  274.  
  275. /*---------------------------------------------------------------------------*
  276.  
  277.     Realize()
  278.  
  279.     This function is called to realize a FileChooser widget.
  280.  
  281.  *---------------------------------------------------------------------------*/
  282.  
  283. static void Realize(w,valueMask,attrs)
  284. Widget w;
  285. XtValueMask *valueMask;
  286. XSetWindowAttributes *attrs;
  287. {
  288.     XfwfFileChooserWidget fcw = (XfwfFileChooserWidget)w;
  289.  
  290.     XtCreateWindow(w,InputOutput,(Visual *)CopyFromParent,*valueMask,attrs);
  291.     ChildrenRealize(fcw);
  292.     ChildrenUpdate(fcw);
  293.     Resize(w);
  294.     Notify(fcw);
  295. } /* End Realize */
  296.  
  297. /*---------------------------------------------------------------------------*
  298.  
  299.     Destroy()
  300.  
  301.     This function is called to destroy a FileChooser widget.
  302.  
  303.  *---------------------------------------------------------------------------*/
  304.  
  305. static void
  306. Destroy(fcw)
  307. XfwfFileChooserWidget fcw;
  308. {
  309.     int i;
  310.  
  311.     XtFree(FCCurrentDirectory(fcw));
  312.     XtFree(FCCurrentFile(fcw));
  313.     XtFree(FCPattern(fcw));
  314.     if (FCFileNames(fcw) != NULL) {
  315.     for (i=0; i < FCNumFileNames(fcw); i++)
  316.         XtFree(FCFileNames(fcw)[i]);
  317.     XtFree((char *)FCFileNames(fcw));
  318.     }
  319.     if (FCDirNames(fcw) != NULL) {
  320.     for (i=0; i < FCNumDirNames(fcw); i++)
  321.         XtFree(FCDirNames(fcw)[i]);
  322.     XtFree((char *)FCDirNames(fcw));
  323.     }
  324. } /* End Destroy */
  325.  
  326. /*---------------------------------------------------------------------------*
  327.  
  328.     Resize()
  329.  
  330.     This function is called to resize a FileChooser widget.
  331.  
  332.  *---------------------------------------------------------------------------*/
  333.  
  334. static void
  335. Resize(w) 
  336. Widget w;
  337. {
  338.     XfwfFileChooserWidget fcw = (XfwfFileChooserWidget)w;
  339.  
  340.     ChildrenUpdate(fcw);
  341. } /* End Resize */
  342.  
  343. /*---------------------------------------------------------------------------*
  344.  
  345.     SetValues()
  346.  
  347.     This function is the external interface for setting resources.
  348.  
  349.  *---------------------------------------------------------------------------*/
  350.  
  351. /* ARGSUSED */
  352. static Boolean
  353. SetValues(current,request,new)
  354. Widget current,request,new;
  355. {
  356.     XfwfFileChooserWidget fcw_current = (XfwfFileChooserWidget)current;
  357.     XfwfFileChooserWidget fcw_new = (XfwfFileChooserWidget)new;
  358.  
  359.     if (FCCurrentDirectory(fcw_current) != FCCurrentDirectory(fcw_new)){
  360.     strcpy(FCCurrentDirectory(fcw_current),FCCurrentDirectory(fcw_new));
  361.     FCCurrentDirectory(fcw_new) = FCCurrentDirectory(fcw_current);
  362.     Chdir(fcw_new);
  363.     }
  364.     if (FCCurrentFile(fcw_current) != FCCurrentFile(fcw_new)) {
  365.     char *new_name;
  366.  
  367.     new_name = FCCurrentFile(fcw_new);
  368.     FCCurrentFile(fcw_new) = FCCurrentFile(fcw_current);
  369.     SelectFileByName(fcw_new,new_name);
  370.     }
  371.     if (FCPattern(fcw_current) != FCPattern(fcw_new)) {
  372.     XtFree(FCPattern(fcw_current));
  373.     FCPattern(fcw_new) = XtNewString(FCPattern(fcw_current));
  374.     Chdir(fcw_new);
  375.     }
  376.     if (FCSortMode(fcw_current) != FCSortMode(fcw_new)) {
  377.     Chdir(fcw_new);
  378.     }
  379.     return(False);
  380. } /* End SetValues() */
  381.  
  382. /*---------------------------------------------------------------------------*
  383.  
  384.     GeometryManager(w,request,reply)
  385.  
  386.     This routine acts as the geometry_manager method for the
  387.     FileChooser widget.  It is called when a child wants to
  388.     resize/reposition itself.
  389.  
  390.     Currently, we allow all requests.
  391.  
  392.  *---------------------------------------------------------------------------*/
  393.  
  394. /* ARGSUSED */
  395. static XtGeometryResult
  396. GeometryManager(w,request,reply)
  397. Widget w;
  398. XtWidgetGeometry *request;
  399. XtWidgetGeometry *reply;
  400. {
  401.     return(XtGeometryYes);
  402. } /* End GeometryManager */
  403.  
  404. /*---------------------------------------------------------------------------*
  405.  
  406.                      L O C A L    R O U T I N E S
  407.  
  408.  *---------------------------------------------------------------------------*/
  409.  
  410. /*---------------------------------------------------------------------------*
  411.  
  412.     ChildrenCreate(fcw)
  413.  
  414.     This routine creates the initial child widgets for the
  415.     file selector widget and places them in the widget fcw.
  416.     No placement or resizing is done.  That is done by
  417.     ChildrenUpdate().
  418.  
  419.  *---------------------------------------------------------------------------*/
  420.  
  421. static void
  422. ChildrenCreate(fcw)
  423. XfwfFileChooserWidget fcw;
  424. {
  425.     Arg args[2];
  426.     static char *str = NULL;
  427.  
  428.     XtSetArg(args[0],XtNmenuName,FC_DIR_MENU_NAME);
  429.     FCDirMenuButton(fcw) =
  430.     XtCreateManagedWidget(FC_DIR_MENU_BUTTON_NAME,menuButtonWidgetClass,
  431.                   (Widget)fcw,args,1);
  432.     XtSetArg(args[0],XtNallowVert,True);
  433.     XtSetArg(args[1],XtNforceBars,True);
  434.     FCFileViewport(fcw) =
  435.     XtCreateManagedWidget(FC_FILE_VIEWPORT_NAME,viewportWidgetClass,
  436.                   (Widget)fcw,args,2);
  437.     XtSetArg(args[0],XtNlist,&str);
  438.     XtSetArg(args[1],XtNverticalList,True);
  439.     FCFileList(fcw) = XtCreateManagedWidget(FC_FILE_LIST_NAME,listWidgetClass,
  440.                         FCFileViewport(fcw),args,2);
  441.     XtAddCallback(FCFileList(fcw),XtNcallback,
  442.           (XtCallbackProc)FileCallback,(XtPointer)fcw);
  443. } /* End ChildrenCreate */
  444.  
  445. /*---------------------------------------------------------------------------*
  446.  
  447.     ChildrenRealize(fcw)
  448.  
  449.     This routine realizes the child widgets.  The widgets must
  450.     already have been created and initialized.  Their coordinates
  451.     should already have been set.
  452.  
  453.  *---------------------------------------------------------------------------*/
  454.  
  455. static void
  456. ChildrenRealize(fcw)
  457. XfwfFileChooserWidget fcw;
  458. {
  459.     XtRealizeWidget(FCDirMenuButton(fcw));
  460.     XtRealizeWidget(FCFileViewport(fcw));
  461.     XtRealizeWidget(FCFileList(fcw));
  462. } /* End ChildrenRealize */
  463.  
  464. /*---------------------------------------------------------------------------*
  465.  
  466.     ChildrenUpdate(fcw)
  467.  
  468.     This routine takes a FileChooser widget fcw and updates
  469.     the child widgets by recalculating their coordinates based
  470.     on the current size of the FileChooser, and setting the
  471.     appropriate resources.
  472.  
  473.     We go to some trouble to get something useful displayed in the
  474.     FCDirMenuButton(fcw) if the current directory name is too long
  475.     to fit in the button. It would be nice if the "justify" resource
  476.     of the MenuButton widget did this, but...
  477.  
  478.  *---------------------------------------------------------------------------*/
  479.  
  480. static void
  481. ChildrenUpdate(fcw)
  482. XfwfFileChooserWidget fcw;
  483. {
  484.     Dimension w,h;
  485.     int gap;
  486.     Dimension menuButtonW,menuButtonH,fileListW,fileListH;
  487.     Position menuButtonX,menuButtonY,fileListX,fileListY;
  488.     XtWidgetGeometry parent_idea,child_idea;
  489.     Arg args[3];
  490.     XFontStruct *fs;
  491.     char *label;
  492.     Dimension intw;
  493.  
  494.     if (!XtIsRealized((Widget)fcw)) {
  495.     return;
  496.     }
  497.     w = CoreWidth(fcw);
  498.     h = CoreHeight(fcw);
  499.     gap = 3;
  500.     /* Get The Child Widgets Current Widths And Heights */
  501.     /* (although we don't actually use the existing values... */
  502.     menuButtonW = CoreWidth(FCDirMenuButton(fcw));
  503.     menuButtonH = CoreHeight(FCDirMenuButton(fcw));
  504.     fileListW = CoreWidth(FCFileList(fcw));
  505.     fileListH = CoreHeight(FCFileList(fcw));
  506.     /* Adjust Widths */
  507.     menuButtonW = w;
  508.     fileListW = w;
  509.     /* Adjust menu button label if too small */
  510.     /* It would be nice if the "justify" resource of MenuButton did this... */
  511.     XtSetArg(args[0],XtNinternalWidth,&intw);
  512.     XtSetArg(args[1],XtNfont,&fs);
  513.     XtGetValues(FCDirMenuButton(fcw),args,2);
  514.     label = FCCurrentDirectory(fcw);
  515.     if (XTextWidth(fs,label,strlen(label)) > (int)(menuButtonW-intw)) {
  516.     char newLabel[MAXPATHLEN];
  517.     while (*label && XTextWidth(fs,label,strlen(label)) >
  518.                                                (int)(menuButtonW-intw)) {
  519.         label += 1;
  520.     }
  521.     if (*label)
  522.         label += 1;
  523.     strcpy(newLabel,"<");
  524.     strcat(newLabel,label);
  525.     XtSetArg(args[0],XtNlabel,newLabel);
  526.     XtSetValues(FCDirMenuButton(fcw),args,1);
  527.     }
  528.     /* Adjust Heights */
  529.     fileListH = h - menuButtonH - gap;
  530.     /* Listen To Child Height Request For List */
  531.     parent_idea.request_mode = CWWidth | CWHeight;
  532.     parent_idea.width = fileListW;
  533.     parent_idea.height = fileListH;
  534.     XtQueryGeometry(FCFileList(fcw),&parent_idea,&child_idea);
  535.     if ((child_idea.request_mode & CWHeight) &&
  536.     (child_idea.height < parent_idea.height)) {
  537.     fileListH = child_idea.height;
  538.     }
  539.     /* Vertical Positions */
  540.     menuButtonY = 0;
  541.     fileListY = menuButtonH + gap;
  542.     /* Horizontal Positions */
  543.     menuButtonX = 0;
  544.     fileListX = 0;
  545.     /* Move them */
  546.     XtMoveWidget(FCDirMenuButton(fcw),menuButtonX,menuButtonY);
  547.     XtMoveWidget(FCFileViewport(fcw),fileListX,fileListY);
  548.     /* Resize them */
  549.     XtResizeWidget(FCDirMenuButton(fcw),menuButtonW,menuButtonH,
  550.            CoreBorderWidth(FCDirMenuButton(fcw)));
  551.     XtResizeWidget(FCFileViewport(fcw),fileListW,fileListH,
  552.            CoreBorderWidth(FCFileViewport(fcw)));
  553. } /* End ChildrenUpdate */
  554.  
  555. /*---------------------------------------------------------------------------*
  556.  
  557.                  I N T E R N A L    C A L L B A C K S
  558.  
  559.  *---------------------------------------------------------------------------*/
  560.  
  561. /*---------------------------------------------------------------------------*
  562.  
  563.     DirectoryCallback(w,client_data,call_data)
  564.  
  565.     This is called when the user selects an ancestor directory from
  566.     the menu. The argument "w" is the selected object (hence the two
  567.     calls to XtParent()) and "client_data" is it's index in the menu.
  568.  
  569.  *---------------------------------------------------------------------------*/
  570.  
  571. /*ARGSUSED*/
  572. static void
  573. DirectoryCallback(w,client_data,call_data)
  574. Widget w;
  575. XtPointer client_data;    /* index */
  576. XtPointer call_data;    /* not used */
  577. {
  578.     int index = (int)client_data;
  579.     XfwfFileChooserWidget fcw = (XfwfFileChooserWidget)XtParent(XtParent(w));
  580.     int i;
  581.  
  582.     strcpy(FCCurrentDirectory(fcw),"/");
  583.     for (i = 1; i <= index; i++) {
  584.     strcat(FCCurrentDirectory(fcw),FCDirNames(fcw)[i]);
  585.     strcat(FCCurrentDirectory(fcw),"/");
  586.     }
  587.     Chdir(fcw);
  588. } /* End DirectoryCallback */
  589.  
  590. /*---------------------------------------------------------------------------*
  591.  
  592.     FileCallback(w,client_data,call_data)
  593.  
  594.     This is called when the user selects a file in the fileList.
  595.     The argument "client_data" is the FileChooser widget, "call_data"
  596.     is a pointer to the standard List widget callback information.
  597.  
  598.  *---------------------------------------------------------------------------*/
  599.  
  600. /*ARGSUSED*/
  601. static void
  602. FileCallback(w,client_data,call_data)
  603. Widget w;
  604. XtPointer client_data;    /* fcw */
  605. XtPointer call_data;    /* return struct */
  606. {
  607.     XfwfFileChooserWidget fcw = (XfwfFileChooserWidget)client_data;
  608.     XawListReturnStruct *ret = (XawListReturnStruct *)call_data;
  609.  
  610.     if (ret->list_index == -1) {
  611.     UnselectAll(fcw);        /* Click On Blank Space */
  612.     Notify(fcw);
  613.     } else {
  614.     SelectFileByIndex(fcw,ret->list_index);
  615.     }
  616. } /* End FileCallback */
  617.  
  618. /*---------------------------------------------------------------------------*
  619.  
  620.              I N T E R N A L    S U P P O R T    R O U T I N E S
  621.  
  622.  *---------------------------------------------------------------------------*/
  623.  
  624. static void
  625. SelectFileByIndex(fcw,index)
  626. XfwfFileChooserWidget fcw;
  627. int index;
  628. {
  629.     DirEntry *dir_entry;
  630.  
  631.     DirectoryMgrGotoItem(FCDirMgr(fcw),index);
  632.     if ((dir_entry=DirectoryMgrCurrentEntry(FCDirMgr(fcw))) == NULL) {
  633.     fprintf(stderr,"SelectFileByIndex: Entry %d invalid\n",index);
  634.     XtAppErrorMsg(XtWidgetToApplicationContext((Widget)fcw),
  635.               "selectFailed","SelectFileByIndex","XfwfError",
  636.               "FileChooser: SelectFileByIndex failed.",
  637.               (String*)NULL,(Cardinal*)NULL);
  638.     }
  639.     if (DirEntryIsDir(dir_entry) || DirEntryIsDirectoryLink(dir_entry)) {
  640.     strcat(FCCurrentDirectory(fcw),DirEntryFileName(dir_entry));
  641.     Chdir(fcw);
  642.     } else if (!DirEntryIsBrokenLink(dir_entry)) {    /* File */
  643.     strcpy(FCCurrentFile(fcw),DirEntryFileName(dir_entry));
  644.     XawListHighlight(FCFileList(fcw),index);
  645.     Notify(fcw);
  646.     } else {                        /* Broken Link */
  647.     XBell(XtDisplay(fcw),0);
  648.     UnselectAll(fcw);
  649.     }
  650. } /* End SelectFileByIndex */
  651.  
  652. static Boolean
  653. SelectFileByName(fcw,name)
  654. XfwfFileChooserWidget fcw;
  655. char *name;
  656. {
  657.     if (DirectoryMgrGotoNamedItem(FCDirMgr(fcw),name) == FALSE) {
  658.     return(False);
  659.     }
  660.     SelectFileByIndex(fcw,DirectoryMgrCurrentIndex(FCDirMgr(fcw)));
  661.     return(True);
  662. } /* End SelectFileByName */
  663.  
  664. static void
  665. UnselectAll(fcw)
  666. XfwfFileChooserWidget fcw;
  667. {
  668.     Boolean selected = FCCurrentFile(fcw)[0] != '\0';
  669.  
  670.     FCCurrentFile(fcw)[0] = '\0';
  671.     XawListUnhighlight(FCFileList(fcw));
  672.     if (selected)
  673.     Notify(fcw);
  674. } /* End UnselectAll */
  675.  
  676. static void
  677. Notify(fcw)
  678. XfwfFileChooserWidget fcw;
  679. {
  680.     XfwfFileChooserReturnStruct ret;
  681.  
  682.     if (FCCurrentFile(fcw)[0] != '\0') {
  683.     ret.directory = FCCurrentDirectory(fcw);
  684.     ret.file = FCCurrentFile(fcw);
  685.     } else {
  686.     ret.directory = NULL;
  687.     ret.file = NULL;
  688.     }
  689.     XtCallCallbacks((Widget)fcw,XtNcallback,(XtPointer)&ret);
  690. } /* End Notify */
  691.  
  692. /*---------------------------------------------------------------------------*
  693.  
  694.     GotoDeepestLegalDirectory(fcw)
  695.  
  696.     This function takes a FileChooser widget <fcw> and modifies the
  697.     directory string in FCCurrentDirectory(fcw) to be the deepest
  698.     legal directory above the string.  Partial or incorrect directory
  699.     names are stripped starting at the end.
  700.  
  701.     It then calls UpdateLists() to reset the information dislayed in
  702.     the FileChooser.
  703.  
  704.  *---------------------------------------------------------------------------*/
  705.  
  706. static void
  707. GotoDeepestLegalDirectory(fcw)
  708. XfwfFileChooserWidget fcw;
  709. {
  710.     char *dir,*end;
  711.     char temp[MAXPATHLEN + 2];
  712.  
  713.     dir = FCCurrentDirectory(fcw);
  714.     for (end=dir; *end != '\0'; ++end)
  715.     /*EMPTY*/;
  716.     while (1) {
  717.     if (DirectoryPathExpand(dir,temp) == NULL) {
  718.         while (*end != '/' && end != dir) {
  719.         end -= 1;
  720.         }
  721.         *end = '\0';
  722.     } else {
  723.         strcpy(FCCurrentDirectory(fcw),temp);
  724.         break;
  725.     }
  726.     }
  727.     UnselectAll(fcw);
  728.     UpdateLists(fcw);
  729. } /* End GotoDeepestLegalDirectory */
  730.  
  731. /*---------------------------------------------------------------------------*
  732.  
  733.     UpdateLists(fcw)
  734.  
  735.     This routine resets the information displayed in a FileChooser
  736.     widget by doing the following:
  737.     1. It changes the cursor to the value of the "busyCursor" resource.
  738.     2. The old directory manager (FCDirMgr(fcw)) is closed and a
  739.        new one opened based on the value of FCCurrentDirectory(fcw).
  740.     3. Any old string arrays are freed, and any existing directory
  741.        menu is destroyed.
  742.     4. A new array of strings (FCFileNames(fcw)) is allocated and filled
  743.        with the names of the files in the directory, then this array
  744.        is used to set what is displayed in the FCFileList(fcw) widget.
  745.     5. A new array of strings (FCDirNames(fcw)) is allocated and filled
  746.        with the names of the ancestor directories. These are also used
  747.        to create a new FCDirMenu(fcw), and the label FCDirMenuButton(fcw)
  748.        is set to the name of the directory.
  749.     6. Finally, the cursor is restored.
  750.  
  751.  *---------------------------------------------------------------------------*/
  752.  
  753. static void
  754. UpdateLists(fcw)
  755. XfwfFileChooserWidget fcw;
  756. {
  757.     Arg args[1];
  758.     int i,count;
  759.     char *dir,*start;
  760.     DirEntry *dir_entry;
  761.     char temp[MAXPATHLEN + 2];
  762.     Widget menuItem;
  763.  
  764.     if (XtIsRealized((Widget)fcw)) {
  765.     /* This is puke-ola. */
  766.     XDefineCursor(XtDisplay(fcw),XtWindow(fcw),FCBusyCursor(fcw));
  767.     XDefineCursor(XtDisplay(fcw),XtWindow(FCFileList(fcw)),
  768.               FCBusyCursor(fcw));
  769.     XDefineCursor(XtDisplay(fcw),XtWindow(FCDirMenuButton(fcw)),
  770.               FCBusyCursor(fcw));
  771.     XFlush(XtDisplay(fcw));
  772.     }
  773.     if (FCDirMgr(fcw))
  774.     DirectoryMgrClose(FCDirMgr(fcw));
  775.     FCDirMgr(fcw) = DirectoryMgrSimpleOpen(FCCurrentDirectory(fcw),
  776.                        FCSortMode(fcw),FCPattern(fcw));
  777.  
  778.     /* Throw away old info */
  779.     if (FCFileNames(fcw) != NULL) {
  780.     for (i = 0; i < FCNumFileNames(fcw); i++)
  781.         XtFree(FCFileNames(fcw)[i]);
  782.     XtFree((char *)FCFileNames(fcw));
  783.     }
  784.     if (FCDirNames(fcw) != NULL) {
  785.     for (i = 0; i < FCNumDirNames(fcw); i++)
  786.         XtFree(FCDirNames(fcw)[i]);
  787.     XtFree((char *)FCDirNames(fcw));
  788.     }
  789.     if (FCDirMenu(fcw) != NULL)
  790.     XtDestroyWidget(FCDirMenu(fcw));
  791.  
  792.     /* Count how many files and dirs we have now */
  793.     FCNumFileNames(fcw) = DirectoryMgrFilteredCount(FCDirMgr(fcw));
  794.     FCNumDirNames(fcw) = 1;
  795.     for (dir=FCCurrentDirectory(fcw)+1; *dir != '\0'; dir++) {
  796.     if (*dir == '/') 
  797.         FCNumDirNames(fcw) += 1;
  798.     }
  799.  
  800.     /* Make the array of filenames and set the fileList widget */
  801.     FCFileNames(fcw) = (char **)XtCalloc(FCNumFileNames(fcw)+1,sizeof(char *));
  802.     for (i=0; i < FCNumFileNames(fcw); i++) {
  803.     dir_entry = DirectoryMgrNextEntry(FCDirMgr(fcw));
  804.     if (dir_entry == NULL)
  805.         XtError("Inconsistent Directory");
  806.     strcpy(temp,DirEntryFileName(dir_entry));
  807.     if (DirEntryIsDir(dir_entry))
  808.         strcat(temp,"/");
  809.     else if (DirEntryIsBrokenLink(dir_entry))
  810.         strcat(temp," X");
  811.     else if (DirEntryIsDirectoryLink(dir_entry))
  812.         strcat(temp,"/");
  813.     else if (DirEntryIsSymLink(dir_entry))
  814.         strcat(temp," @");
  815.     FCFileNames(fcw)[i] = XtNewString(temp);
  816.     }
  817.     FCFileNames(fcw)[i] = NULL;
  818.     XawListChange(FCFileList(fcw),FCFileNames(fcw),FCNumFileNames(fcw),0,True);
  819.  
  820.     /* Make the array of dirnames and build a new dirMenu widget */
  821.     FCDirNames(fcw) = (char **)XtCalloc(FCNumDirNames(fcw)+1,sizeof(char *));
  822.     FCDirNames(fcw)[0] = XtNewString("/");
  823.     FCDirMenu(fcw) = XtCreatePopupShell(FC_DIR_MENU_NAME,simpleMenuWidgetClass,
  824.                     (Widget)fcw,NULL,0);
  825.     menuItem = XtCreateManagedWidget("/",smeBSBObjectClass,FCDirMenu(fcw),
  826.                      NULL,0);
  827.     XtAddCallback(menuItem,XtNcallback,DirectoryCallback,(XtPointer)0);
  828.     start = FCCurrentDirectory(fcw);
  829.     for (i = 1; i < FCNumDirNames(fcw); i++) {
  830.     while (*start != '\0' && *start == '/')
  831.         start += 1;
  832.     count = 0;
  833.     while (*start != '\0' && *start != '/')
  834.         temp[count++] = *start++;
  835.     temp[count] = '\0';
  836.     FCDirNames(fcw)[i] = XtNewString(temp);
  837.     XtSetArg(args[0],XtNlabel,temp);
  838.     menuItem = XtCreateManagedWidget("dirMenuItem",smeBSBObjectClass,
  839.                      FCDirMenu(fcw),args,1);
  840.         XtAddCallback(menuItem,XtNcallback,DirectoryCallback,(XtPointer)i);
  841.     }
  842.     XtSetArg(args[0],XtNlabel,FCCurrentDirectory(fcw));
  843.     XtSetValues(FCDirMenuButton(fcw),args,1);
  844.     if (XtIsRealized((Widget)fcw)) {
  845.     XUndefineCursor(XtDisplay(fcw),XtWindow(fcw));
  846.     XUndefineCursor(XtDisplay(fcw),XtWindow(FCFileList(fcw)));
  847.     XUndefineCursor(XtDisplay(fcw),XtWindow(FCDirMenuButton(fcw)));
  848.     }
  849. } /* End UpdateLists */
  850.  
  851. static void Chdir(fcw)
  852. XfwfFileChooserWidget fcw;
  853. {
  854.     GotoDeepestLegalDirectory(fcw);
  855.     ChildrenUpdate(fcw);
  856. } /* End Chdir */
  857.  
  858. /*---------------------------------------------------------------------------*
  859.  
  860.                     E X T E R N A L    R O U T I N E S
  861.  
  862.  *---------------------------------------------------------------------------*/
  863.  
  864. void
  865. XfwfFileChooserChangeDirectory(fcw,dir)
  866. XfwfFileChooserWidget fcw;
  867. char *dir;
  868. {
  869.     strcpy(FCCurrentDirectory(fcw),dir);
  870.     Chdir(fcw);
  871. } /* End XfwfFileChooserChangeDirectory */
  872.  
  873. void
  874. XfwfFileChooserRefresh(fcw)
  875. XfwfFileChooserWidget fcw;
  876. {
  877.     XfwfFileChooserChangeDirectory(fcw,".");
  878. } /* End XfwfFileChooserRefresh */
  879.  
  880. char *
  881. XfwfFileChooserCurrentDirectory(fcw)
  882. XfwfFileChooserWidget fcw;
  883. {
  884.     return(FCCurrentDirectory(fcw));
  885. } /* End XfwfFileChooserCurrentDirectory */
  886.  
  887. char *
  888. XfwfFileChooserCurrentFile(fcw)
  889. XfwfFileChooserWidget fcw;
  890. {
  891.     return(FCCurrentFile(fcw));
  892. } /* End XfwfFileChooserCurrentFile */
  893.  
  894.